package com.zombie.logic.object;

import java.util.ArrayList;
import java.util.concurrent.ScheduledFuture;

import com.badlogic.gdx.graphics.Color;
import com.zombie.ResourceManager;
import com.zombie.effect.BloodEffect;
import com.zombie.effect.ScoreEffect;
import com.zombie.logic.core.ZombieWorld;
import com.zombie.logic.enums.AnimationType;
import com.zombie.logic.item.Item;
import com.zombie.logic.item.Weapon;
import com.zombie.logic.object.ai.AI;
import com.zombie.logic.object.ai.NullAI;
import com.zombie.logic.object.stat.BasicStat;
import com.zombie.state.GameState;
import com.zombie.util.Utils;

public abstract class LiveObject extends GameObject {

	public GameObject target;
	public Weapon weapon;
	public long lastStep = 0;
	public ScheduledFuture<?> reload = null;
	protected AI ai;
	protected BasicStat stats;
	boolean dead = false;
	
	protected int lastMoveTimer;
	protected int stepTime = 400;
	protected long hitTime = 1000;
	protected long deathTime = -1;
	protected long lastHit;
	protected ArrayList<Item> drop = new ArrayList<Item>();
	
	private int damage = 5;	
	long walkStarted = 0;
	
	public LiveObject(float x, float y) {
		super(x, y);
	}

	public LiveObject(float x, float y,String img) {
		super(x, y);
		image= img;
	}
	
	public LiveObject(float x, float y,String img,int w,int h) {
		this(x, y,img);
		size.set(w,h);
	}
	
	abstract protected void onHit(GameObject damager);
	
	public void setMaxHp(int i) {
		if (i <= 0)
			return;
		getStat().maxHp = i;
		setHp(i);
	}
	
	public void removeHp(int value, GameObject damager){
		if (getHp() <= 0 || isDead()){
			return;
		}
		value -= getStat().defence;
		if (value <= 0)
			value = 1;
		
		if (damager == GameState.getInstance().player)
			GameState.getInstance().player.hits++;
		onHit(damager);
		getAI().onHit(damager);
		setHp(getHp()-value);
		if (getHp() <= 0)
			doDie(damager,value);
		
		addEffect(value,damager);
	}
	
	protected void playSound() {
		ResourceManager.getSound("punch_"+Utils.rnd.nextInt(3)).play();
	}

	private void addEffect(int damage,GameObject damager) {
		int count = 2 + damage/15;
		if (count > 12)
			count = 12;
		for(int i = 0 ; i< count;i++){
			BloodEffect effect = new BloodEffect();
			effect.position = position.cpy();
			effect.upSpeed += -4f + 6*Utils.rnd.nextFloat();
			effect.angle = (float) damager.getAngleToObject(this) + (-60+Utils.rnd.nextInt(120));
			effect.velocity = 0.2f + 0.2f*Utils.rnd.nextFloat()+damage/100f*Utils.rnd.nextFloat();
			ZombieWorld.addEffect(effect);
		}
		playSound();
	}

	protected void doDie(GameObject killer, int value){
		dead = true;
		deathTime = GameState.time;
		animation = AnimationType.DIE;
		if (killer == GameState.getInstance().player){
			GameState.getInstance().player.kills++;
			GameState.getInstance().player.setExp(GameState.getInstance().player.getExp()
					+ (getMaxHp()/15));
			int money = getMaxHp()/5*getLevel() + getStat().defence;
			money = Math.round(money*getVelocity()*10);
			GameState.getInstance().player.money+= money;
			ScoreEffect eff = new ScoreEffect();
			eff.count = money;
			eff.position.set(position);
			eff.color = Color.GREEN;
			ZombieWorld.addEffect(eff);
		}
		if (!drop.isEmpty())
			doDrop();
		getAI().doDie(killer);
	}
	
	protected void doDrop() {
		for(Item it : drop){
			ItemObject item = new ItemObject(position.x,position.y, it);
			ZombieWorld.addObject(item);
		}
		drop.clear();
		drop= null;
	}

	@Override
	public boolean isDead(){
		return dead;
	}
	
	
	public void addDrop(Item item){
		if (!drop.contains(item))
			drop.add(item);
	}
	
	@Override
	public void createBody() {
		if (size.x == size.y)
			body = ZombieWorld.createNpcCircle(position.x, position.y, size.x/2-size.x/8);
		else
			body = ZombieWorld.createNpcBox(position.x, position.y, size.x-size.x/8,size.y-size.x/8); 
		body.setUserData(this);
	}
	
	public int getHp() {
		return getStat().hp;
	}
	
	public int getLevel() {
		return getStat().level;
	}

	public void setHp(int hp) {
		getStat().hp = hp;
	}

	public int getMaxHp() {
		return getStat().maxHp;
	}
	
	protected void stepSound() {
//		String sound = GameState.getSoundForTile(this);
//		try{
//		ResourceManager.getSound(sound+Utils.rnd.nextInt(4)).play(1f+(-0.3f+0.6f*Utils.rnd.nextFloat()), 0.4f);
//		}catch(Exception e){e.printStackTrace();}
		lastStep = GameState.time;
	}

	public int getDamage() {
		return damage;
	}

	public void setDamage(int damage) {
		this.damage = damage;
	}

	public BasicStat getStat(){
		if (stats == null)
			stats = new BasicStat();
		return stats;
	}
	
	public AI getAI(){
		if (ai == null)
			ai = new NullAI(this);
		return ai;
	}
	
}
